package com.google.code.maven2.plugins.hotswap;

import com.google.code.maven2.plugins.hotswap.support.ClassFileFilter;
import com.google.code.maven2.plugins.hotswap.support.DirectoryFileFilter;
import com.pyx4j.log4j.MavenLogAppender;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugin.logging.SystemStreamLog;

import java.io.File;
import java.net.URL;

/**
 * <pre>
 * Used source from
 *
 * http://code.google.com/p/hotswap/source/browse/trunk/java/dak/ant/taskdefs/Hotswap.java
 *
 * To create a hotswap mojo.
 *
 * Also see, http://another-lazy-blogger.blogspot.com/2008/04/how-to-hotswap-classes-in-running.html
 * </pre>
 *
 * @author Mike Nereson
 * @goal hotswap
 * @phase install
 * @since 1.0
 */
public class HotswapMojo
        extends AbstractMojo
{
    protected Log log;

    private static final String FAIL_MSG = "Hotswap failed; changes to class(es) might not be compatible with replacement on your VM.";

    /**
     * @required
     * @parameter expression="${host}"
     */
    protected String host;

    /**
     * @required
     * @parameter expression="${port}"
     */
    protected String port;

    /**
     * @parameter expression="${project}"
     */
    protected org.apache.maven.project.MavenProject mavenProject;

    /**
     * @goal hotswap
     */
    public void execute()
            throws MojoExecutionException, MojoFailureException
    {
        MavenLogAppender.startPluginLog(this);
        log = getLog();

        try
        {
            final File artifactFile = getGeneratedArtifactFile();
            doExecute(artifactFile);
        }
        catch (Exception e)
        {
            log.error("Failed to hotswap: " + e.getMessage());
        }
        finally
        {
            MavenLogAppender.endPluginLog(this);
        }
    }

    private void doExecute(File artifactFile)
            throws Exception
    {
        final File targetDirectory = artifactFile.getParentFile();

        final File classesDirectory = new File(targetDirectory, "classes");

        log.info("Hotswapping classes from " + classesDirectory.getAbsolutePath());

        HotSwapHelper hotSwapHelper = new HotSwapHelper(log);
        hotSwapHelper.connect(host, port);

        log.info("\tConnected to " + host + ":" + port);

        try
        {
            processHotswap(hotSwapHelper, classesDirectory);
        }
        finally
        {
            log.info("\tFinished processing classes");
            hotSwapHelper.disconnect();
        }
    }

    /**
     * Get the artifact File generated by this maven build.
     *
     * @return File the jar file
     */
    protected final File getGeneratedArtifactFile()
    {
        final Artifact artifact = mavenProject.getArtifact();
        final File artifactFile = artifact.getFile();

        log.info("\tWorking with generated artifact " + artifact.getFile().getName());

        return artifactFile;
    }

    private void processHotswap(HotSwapHelper hotSwapHelper, File file)
            throws Exception
    {
        log.debug("\t\tprocessHotswap");
        log.debug("\t\tFile " + file);

        if (file.isDirectory())
        {
            log.info("\t\t\tProcessing directory " + file.getAbsolutePath());

            final File[] directories = file.listFiles(DirectoryFileFilter.DIRECTORY);

            for (File subDirectory : directories)
            {
                processHotswap(hotSwapHelper, subDirectory);
            }

            final File[] files = file.listFiles(ClassFileFilter.CLAZZ);

            for (File childFile : files)
            {
                log.info("\t\t\t\tSwapping file " + childFile.getName());
                processHotswap(hotSwapHelper, childFile);
            }
        }
        else if (ClassFileFilter.INSTANCE.accept(file))
        {
            String className = file.getAbsolutePath();
            className = className.substring(0, className.length() - 6);       // chop off ".class"
            className = className.replace('/', '.');
            className = className.replace('\\', '.');
            className = className.substring(className.indexOf("classes") + "classes".length());

            log.debug("\t\tHotswapping " + className);

            hotSwapHelper.replace(new URL("file:/" + file.getAbsolutePath()), className);
        }
    }

    private void processDirectory(HotSwapHelper hsh, File d, String subdir)
            throws Exception
    {
        File[] files = new File(d, subdir).listFiles();
        for (int i = 0; i < files.length; i++)
        {
            if (files[i].isDirectory())
            {
                //processDirectory(hsh, d, getClassOrPackage(d, files[i]));
            }
            else
            {
                //processHotswap(hsh, d, getClassOrPackage(d, files[i]));
            }
        }
    }

    private String getClassOrPackage(File baseDir, File fileOrDir)
    {
        return fileOrDir.getAbsolutePath().substring(baseDir.getAbsolutePath().length() + 1);
    }

    public static void main(String[] args)
            throws Exception
    {
        HotswapMojo hotswapMojo = new HotswapMojo();
        hotswapMojo.log = new SystemStreamLog();
        hotswapMojo.port = "5005";
        hotswapMojo.host = "localhost";

        hotswapMojo.doExecute(new File("C:\\dev\\svnlocal\\5x\\standardvbook\\target\\retrieve-standard-vbook-5.5.jar"));
    }
}
